#include "GLWidget.hpp"

GLWidget::GLWidget( QWidget *parent ) :
        QGLWidget( QGLFormat( QGL::NoOverlay | QGL::Rgba | QGL::StencilBuffer | QGL::DoubleBuffer | QGL::DepthBuffer ), parent )
{
    setAutoFillBackground(false);
    m_WKeyPressed = false;
    m_AKeyPressed = false;
    m_SKeyPressed = false;
    m_DKeyPressed = false;
    m_QKeyPressed = false;
    m_EKeyPressed = false;
    m_ShiftKeyPressed = false;

	setFocusPolicy( Qt::StrongFocus );
	
	m_camera = new Camera();
	Renderer::setMainCamera( m_camera );

    frameCount = 0;
    reportFrameTimer.setSingleShot( false );
    reportFrameTimer.setInterval( 1000 );
    reportFrameTimer.connect( &reportFrameTimer, SIGNAL(timeout()),
                              this, SLOT(reportFrameRate()) );
    reportFrameTimer.start();

    redrawTimer.setSingleShot( true );
    redrawTimer.connect( &redrawTimer, SIGNAL(timeout()),
                         this, SLOT(forceRedraw()) );
    redrawTimer.start( 0 );
}

GLWidget::~GLWidget()
{
}

QSize GLWidget::minimumSizeHint() const
{
    return QSize( 50, 50 );
}

QSize GLWidget::sizeHint() const
{
    return QSize( 800, 600 );
}

void GLWidget::initializeGL()
{
    GLenum err = glewInit();
    if( err != GLEW_OK ) {
        QString msg( (char*)glewGetErrorString(err) +
                     QString( ", glew version [" ) +
                     (char*)glewGetString(GLEW_VERSION) +
                     QString( "], gl version [" ) +
                     (char*)glGetString( GL_VERSION ) +
                     QString( "]" ) );
        Logger::write( "GLWidget", "initializeGL()", msg, Logger::Error );
        exit( 0 );
    }
    Renderer::initialize();
}

void GLWidget::resizeGL( int width, int height )
{
	Renderer::resize( width, height );
}

void GLWidget::paintGL()
{
    Renderer::frame();
}

void GLWidget::mousePressEvent(QMouseEvent *event)
{
    currentMouseButtons = event->buttons();
    lastPos = event->pos();
}

void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
	if( currentMouseButtons & Qt::LeftButton )
	{
		int dx = event->x() - lastPos.x();
		int dy = event->y() - lastPos.y();

        m_camera->rotate( ( (float)dy ) * 0.25f,
                          ( (float)dx ) * 0.25f,
                          0.0 );
    }
	
    if( 90.0 < m_camera->rotX() && m_camera->rotX() < 270.0 ) {
        m_camera->setRotation( 180.0 - m_camera->rotX(),
                               m_camera->rotY(),
                               m_camera->rotZ() );
    }

    lastPos = event->pos();
	updateGL();
}

void GLWidget::keyPressEvent ( QKeyEvent * e )
{
    switch( e->key() )
	{
		case Qt::Key_A:
            m_AKeyPressed = true;
			break;
		case Qt::Key_D:
            m_DKeyPressed = true;
			break;
		case Qt::Key_W:
            m_WKeyPressed = true;
			break;
        case Qt::Key_S:
            m_SKeyPressed = true;
            break;
        case Qt::Key_Q:
            m_QKeyPressed = true;
            break;
        case Qt::Key_E:
            m_EKeyPressed = true;
            break;
        case Qt::Key_Shift:
            m_ShiftKeyPressed = true;
            break;
	}
	
	updateGL();
}

void GLWidget::keyReleaseEvent( QKeyEvent *e )
{
    switch( e->key() )
    {
        case Qt::Key_A:
            m_AKeyPressed = false;
            break;
        case Qt::Key_D:
            m_DKeyPressed = false;
            break;
        case Qt::Key_W:
            m_WKeyPressed = false;
            break;
        case Qt::Key_S:
            m_SKeyPressed = false;
            break;
        case Qt::Key_Q:
            m_QKeyPressed = false;
            break;
        case Qt::Key_E:
            m_EKeyPressed = false;
            break;
        case Qt::Key_Shift:
            m_ShiftKeyPressed = false;
            break;
    }

    updateGL();
}

void GLWidget::forceRedraw()
{
    updateGL();
    redrawTimer.start( 0 );
}

void GLWidget::reportFrameRate()
{
    lastFPS = frameCount;
    frameCount = 0;

    Logger::write( "GLWidget", "reportFrameRate()",
                   QString::number( lastFPS ) + " frames/second",
                   Logger::Note );

}

void GLWidget::updateGL()
{
    frameCount++;
    integrateCamera();
    QGLWidget::updateGL();
}

void GLWidget::integrateCamera()
{
    const float speed = 5.0; // meters/second
    int clockDiff = clock() - lastTick;
    lastTick = clock();
    const float dist = ( speed * (float)clockDiff ) /
                       ( m_ShiftKeyPressed ? ( (float)CLOCKS_PER_SEC / 10.0 ) :
                         (float)CLOCKS_PER_SEC );

    float ry = m_camera->rotY();
    while( ry < 0.0 )
        ry += 360.0;
    while( ry > 360.0 )
        ry -= 360.0;

    float c = cos( ry / 57.296 );
    float s = sin( ry / 57.296 );
    float dx = dist * s;
    float dz = dist * c;

    if( m_AKeyPressed ) {
        m_camera->translate( dz, 0, dx );
    }
    if( m_DKeyPressed ) {
        m_camera->translate( -dz, 0, -dx );
    }
    if( m_WKeyPressed ) {
        m_camera->translate( -dx, 0, dz );
    }
    if( m_SKeyPressed ) {
        m_camera->translate( dx, 0, -dz );
    }
    if( m_QKeyPressed ) {
        m_camera->translate( 0, dist, 0 );
    }
    if( m_EKeyPressed ) {
        m_camera->translate( 0, -dist, 0 );
    }
}
